﻿/* EllipseFitter_Qt.cpp
 * 
 * Copyright (C) 2020, 2021 Yuan LI
 * email:18069211@qq.com
 * https://blog.csdn.net/liyuanbhu
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "EllipseFitter_Qt.h"

EllipseFitter_Qt::EllipseFitter_Qt()
{
    x_mean = 0;
    y_mean = 0;
    r1 = 0;
    r2 = 0;
    theta = 0;
}

QPointF center(const QImage &image, int value)
{
    if( image.isNull() || (image.format() != QImage::Format_Indexed8 && image.format() != QImage::Format_Grayscale8) )
    {
        return QPointF(-1, -1);
    }
    int width = image.width();
    int height = image.height();
    int x_mean = 0;
    int y_mean = 0;
    int count = 0;
    for(int j = 0; j < height; j ++)
    {
        const uchar * p = image.constScanLine(j);
        for(int i = 0; i < width; i++)
        {
            if( p[i] == value )
            {
                x_mean += i;
                y_mean += j;
                count++;
            }
        }
    }
    return QPointF((double)x_mean / count, (double)y_mean / count);
}

bool EllipseFitter_Qt::fit(QImage grayImage, int value)
{
    if( grayImage.isNull() ||
            (grayImage.format() != QImage::Format_Indexed8 && grayImage.format() != QImage::Format_Grayscale8) )
    {
        return false;
    }
    center(grayImage, value);
    int width = grayImage.width();
    int height = grayImage.height();
    double n01 = x_mean;
    double n10 = y_mean;
    double mu20 = 0.0;
    double mu02 = 0.0;
    double mu11 = 0.0;
    int count = 0;
    for(int row = 0; row < height; row ++)
    {
        const uchar * p = grayImage.constScanLine(row);
        for(int col = 0; col < width; col++)
        {
            if( p[col] == value )
            {
                mu02 += (col - n01) * (col - n01);
                mu20 += (row - n10) * (row - n10);
                mu11 += (col - n01) * (row - n10);
                count ++;
            }
        }
    }
    if(count == 0)
    {
        return false;
    }
    mu20 /= count;
    mu02 /= count;
    mu11 /= count;
    double t1 = mu20 + mu02;
    double t2 = mu20 - mu02;
    double t3 = sqrt(t2 * t2 + 4 * mu11 * mu11);
    r1 = sqrt(2 * ( t1 + t3) );
    r2 = sqrt(2 * ( t1 - t3) );
    theta = - atan2(2 * mu11, mu02 - mu20) / 2.0;

    return true;
}

bool EllipseFitter_Qt::center(QImage grayImage, int value)
{
    if( grayImage.isNull() ||
            (grayImage.format() != QImage::Format_Indexed8 && grayImage.format() != QImage::Format_Grayscale8) )
    {
        return false;
    }
    int width = grayImage.width();
    int height = grayImage.height();
    x_mean = 0;
    y_mean = 0;
    int count = 0;
    for(int j = 0; j < height; j ++)
    {
        const uchar * p = grayImage.constScanLine(j);
        for(int i = 0; i < width; i++)
        {
            if( p[i] == value )
            {
                x_mean += i;
                y_mean += j;
                count++;
            }
        }
    }
    if(count == 0)
    {
        return false;
    }
    x_mean /= count;
    y_mean /= count;
}
